本系列文章已出版實體書籍:
「你的地圖會說話?WebGIS 與 JavaScript 的情感交織」(博碩文化)
WebGIS啟蒙首選✖五家地圖API✖近百個程式範例✖實用簡易口訣✖學習難度分級✖補充ES6小知識
本篇文章請搭配
[3D地圖-CesiumJS系列] 一、快速上手
不知道大家在飛機上時會不會好奇飛機行進到哪裡?
飛行高度多少?飛行軌跡如何?身為好奇寶寶的我們,常常會盯著座位螢幕前的3D飛航示意圖呢!
今天就要來介紹怎麼使用CesiumJS來製作一個飛航軌跡圖。
本篇文章使用官方範例來介紹。
複習一下昨天介紹的初始化地圖的方式吧!如果還不會CesiumJS專案建置的人,請參考昨天的文章。
在根目錄下建立一個html頁面,取名為Cesium_airplane.html。
↓ 建立一個存放地圖的div
<div id="cmap"></div>
↓ 引入Cesium.js
<script src="../Build/Cesium/Cesium.js"></script>
↓ 引入css
<link rel="stylesheet" href="../Build/Cesium/Widgets/widgets.css" />
↓ css讓地圖滿版
<style>
html,
body,
#cmap {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
↓ 設定API Key,如果想要載入自己上傳的圖層或模型,就要載入自己的key,官網註冊連結。
Cesium.Ion.defaultAccessToken = yourAPIKey;
↓ 初始化地圖,新建一個Cesium.Viewer的物件,第一個參數存放地圖的容器Id,第二個參數為設定(選填)。
const viewer = new Cesium.Viewer('cmap', {
terrainProvider: Cesium.createWorldTerrain() // 建立地形
});
↓ 結果
↓ 花東縱谷,未使用Cesium.createWorldTerrain()
↓ 花東縱谷,使用Cesium.createWorldTerrain()
明顯較能感受到地形高低起伏。
↓ 建立3D建物的圖層
const osmBuildings = viewer.scene.primitives.add(Cesium.createOsmBuildings());
↓ 台北信義區,未使用Cesium.createOsmBuildings()
頂多出現高樓層建築物的陰影。
↓ 台北信義區,使用Cesium.createOsmBuildings()
只要有登記3D建模的建築物都會清楚呈現。
這邊為求方便,直接使用範例航班數據下載。
↓ 資料格式
const data = [{ "longitude": 121.523333, "latitude": 25.15, "height": 3000 }, { "longitude": 120.3508, "latitude": 23, "height": 12000 }]
↓ 把讀取的json資料格式轉為物件/陣列後,即可使用。
const flightData = JSON.parse(data);
↓ 設定時間區間、起始時間、時間軸動畫
const timeSpan = 30;
const totalSeconds = timeSpan * (flightData.length - 1);
const start = Cesium.JulianDate.fromIso8601("2020-10-13T21:10:00Z");
const stop = Cesium.JulianDate.addSeconds(start, totalSeconds, new Cesium.JulianDate());
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.timeline.zoomTo(start, stop);
viewer.clock.multiplier = 50;
viewer.clock.shouldAnimate = true;
↓ 時間軸由設定的時間開始跑
↓ 剛剛設定的時間區間及每個點座標資訊,用Cesium.SampledPositionProperty()建立的物件來儲存。
const timeSpan = 30;
const positionProperty = new Cesium.SampledPositionProperty();
↓ 跑迴圈,設定每個點的時間區間、座標、高度,並把它們加入positionProperty物件中,最後並把點加入地圖(viewer)中。
flightData.forEach((item, index) => {
const time = Cesium.JulianDate.addSeconds(start, index * timeSpan, new Cesium.JulianDate());
const position = Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, item.height);
positionProperty.addSample(time, position);
viewer.entities.add({
description: `經度: ${item.longitude}, 緯度: ${item.latitude}, 海拔高度: ${item.height})`,
position: position,
point: { pixelSize: 10, color: Cesium.Color.ORANGE }
});
});
↓ 飛航軌跡
↓ 從側面看,飛航軌跡橫越大西洋
↓ 把地圖投影成平面後,會發現最短距離在平面地圖上是弧形的
可以在Cesium的官方平台上,上傳飛機模型,上傳完畢後會得到一組飛行模型的Id。
↓ 上傳介面
↓ 選擇GITF格式
↓ 上傳成功,獲得該飛行模型的Id。
↓ 地圖載入飛機模型,並將它設定至飛航軌跡的實體。
const airPlaneId = 164161;
async function LoadAirPlaneModel() {
const airplaneUri = await Cesium.IonResource.fromAssetId(airPlaneId);
const airplane = {
availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start: start, stop: stop })]),
position: positionProperty,
model: { uri: airplaneUri },
orientation: new Cesium.VelocityOrientationProperty(positionProperty),
path: new Cesium.PathGraphics({ width: 3 })
}
viewer.trackedEntity = viewer.entities.add(airplane);
}
↓ airplaneUri也可以直接讀取官網的範例飛機模型連結。
const airplaneUri = 'https://sandcastle.cesium.com/SampleData/models/CesiumAir/Cesium_Air.glb';
↓ 呼叫
LoadAirPlaneModel();
↓ 機場中滑行
↓ 空中轉向
↓ 快速飛越陸地
↓ 海面上飛行
看著飛機再飛是不是很療癒呢?
大家趕快也來玩看看吧!